home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / security / log_tcp_6.0alpha.shar / from_sock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-02  |  7.9 KB  |  311 lines

  1.  /*
  2.   * from_sock() determines the type of socket (datagram, stream), the name
  3.   * and address of the host at the other end of standard input, and the
  4.   * remote user name (if RFC 931 lookups are enabled). A host name of "stdin"
  5.   * is returned if the program is run from a tty. All results are in static
  6.   * or allocated memory. from_sock() assumes that its result argument is
  7.   * already initialized with default values.
  8.   * 
  9.   * The return status is (-1) if the remote host pretends to have someone elses
  10.   * host name, otherwise a zero status is returned.
  11.   * 
  12.   * Diagnostics are reported through syslog(3).
  13.   * 
  14.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  15.   */
  16.  
  17. #ifndef lint
  18. static char sccsid[] = "@(#) from_sock.c 1.1 93/07/02 16:33:48";
  19. #endif
  20.  
  21. /* System libraries. */
  22.  
  23. #include <sys/types.h>
  24. #include <sys/param.h>
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <netdb.h>
  28. #include <stdio.h>
  29. #include <syslog.h>
  30. #include <errno.h>
  31.  
  32. extern char *inet_ntoa();
  33. extern char *strncpy();
  34. extern char *strcpy();
  35.  
  36. /* In case not defined in <sys/param.h>. */
  37.  
  38. #ifndef MAXHOSTNAMELEN
  39. #define MAXHOSTNAMELEN    1024        /* string with host name */
  40. #endif
  41.  
  42. /* Local stuff. */
  43.  
  44. #include "log_tcp.h"
  45.  
  46. /* Forward declarations. */
  47.  
  48. static int ip_match();
  49. static void udp_sink();
  50.  
  51. /* The following are to be used in assignment context, not in comparisons. */
  52.  
  53. #define    GOOD    1
  54. #define    BAD    0
  55.  
  56.  /*
  57.   * With early SunOS 5 versions, recvfrom() does not completely fill in the
  58.   * source address structure when doing a non-destructive read. The following
  59.   * code works around the problem. It does no harm on "normal" systems.
  60.   */
  61.  
  62. #ifdef RECVFROM_BUG
  63.  
  64. static int fix_recvfrom(sock, buf, buflen, flags, from, fromlen)
  65. int     sock;
  66. char   *buf;
  67. int     buflen;
  68. int     flags;
  69. struct sockaddr *from;
  70. int    *fromlen;
  71. {
  72.     int     ret;
  73.  
  74.     /* Assume that both ends of a socket belong to the same address family. */
  75.  
  76.     if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) {
  77.     if (from->sa_family == 0) {
  78.         struct sockaddr my_addr;
  79.         int     my_addr_len = sizeof(my_addr);
  80.  
  81.         if (getsockname(0, &my_addr, &my_addr_len)) {
  82.         syslog(LOG_ERR, "getsockname: %m");
  83.         } else {
  84.         from->sa_family = my_addr.sa_family;
  85.         }
  86.     }
  87.     }
  88.     return (ret);
  89. }
  90.  
  91. #define recvfrom fix_recvfrom
  92. #endif
  93.  
  94.  /*
  95.   * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an
  96.   * error in case of a datagram-oriented socket. Instead, they claim that all
  97.   * UDP requests come from address 0.0.0.0. The following code works around
  98.   * the problem. It does no harm on "normal" systems.
  99.   */
  100.  
  101. #ifdef GETPEERNAME_BUG
  102.  
  103. static int fix_getpeername(sock, sa, len)
  104. int     sock;
  105. struct sockaddr *sa;
  106. int    *len;
  107. {
  108.     int     ret;
  109.     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
  110.  
  111.     if ((ret = getpeername(sock, sa, len)) >= 0
  112.     && sa->sa_family == AF_INET
  113.     && sin->sin_addr.s_addr == 0) {
  114.     errno = ENOTCONN;
  115.     return (-1);
  116.     } else {
  117.     return (ret);
  118.     }
  119. }
  120.  
  121. #define    getpeername    fix_getpeername
  122. #endif
  123.  
  124. /* from_sock - find out what is at the other end of standard input */
  125.  
  126. int     from_sock(f)
  127. struct from_host *f;
  128. {
  129.     static struct sockaddr sa;
  130.     struct sockaddr_in *sin = (struct sockaddr_in *) (&sa);
  131.     int     length = sizeof(sa);
  132.     char    buf[BUFSIZ];
  133.  
  134.     /*
  135.      * Look up the remote host address. Hal R. Brand <BRAND@addvax.llnl.gov>
  136.      * suggested how to get the remote host info in case of UDP connections:
  137.      * peek at the first message without actually looking at its contents.
  138.      */
  139.  
  140.     if (getpeername(0, &sa, &length) >= 0) {    /* assume TCP request */
  141.     f->sock_type = FROM_CONNECTED;
  142.     } else {
  143.     switch (errno) {
  144.     default:
  145.         if (isatty(0))            /* stdin is not a socket */
  146.         f->name = "stdin";
  147.         else
  148.         syslog(LOG_ERR, "getpeername: %m");    /* other, punt */
  149.         return (0);
  150.     case ENOTCONN:                /* assume UDP request */
  151.         length = sizeof(sa);
  152.         if (recvfrom(0, buf, sizeof(buf), MSG_PEEK, &sa, &length) < 0) {
  153.         syslog(LOG_ERR, "recvfrom: %m");
  154.         return (0);
  155.         }
  156. #ifdef really_paranoid
  157.         memset(buf, 0 sizeof(buf));
  158. #endif
  159.         f->sock_type = FROM_UNCONNECTED;
  160.         f->sink = udp_sink;
  161.         break;
  162.     }
  163.     }
  164.  
  165.     /*
  166.      * At present, we can only deal with the AF_INET address family. Some
  167.      * implementations of System V religion never fill in the address family
  168.      * field in case of UDP connections. If that happens, you may want to
  169.      * take the chance and assume that we're dealing with TCP/IP anyway.
  170.      */
  171.  
  172. #ifdef ADDRESS_FAMILY_BUG
  173.     if (sa.sa_family == 0)
  174.     sa.sa_family = AF_INET;
  175. #endif
  176.     if (sa.sa_family != AF_INET) {
  177.     syslog(LOG_ERR, "unexpected address family %ld", (long) sa.sa_family);
  178.     return (0);
  179.     }
  180.     return (ip_host(f, sin));
  181. }
  182.  
  183. /* ip_host - map an IP address structure to human-readable address and name */
  184.  
  185. int     ip_host(f, sin)
  186. struct from_host *f;
  187. struct sockaddr_in *sin;
  188. {
  189.     static char addr_buf[FROM_ADDRLEN];
  190.     static char name_buf[MAXHOSTNAMELEN];
  191.     struct hostent *hp;
  192.  
  193.     /*
  194.      * Keep the client sockaddr info in case we want to look up the remote
  195.      * user. Save the host address. A later inet_ntoa() call may clobber it.
  196.      */
  197.  
  198.     f->sin = sin;
  199.     f->addr = strcpy(addr_buf, inet_ntoa(sin->sin_addr));
  200.  
  201.     /*
  202.      * Look up the remote user name. Does not work for UDP services, and may
  203.      * cause noticeable delays with non-UNIX clients.
  204.      */
  205.  
  206. #ifdef RFC931
  207.     if (f->sock_type == FROM_CONNECTED)
  208.     f->user = rfc931_name(sin);
  209. #endif
  210.  
  211.     /*
  212.      * Look up the remote host name and make a copy, or a later
  213.      * gethostbyxxx() call may clobber it.
  214.      */
  215.  
  216.     if ((hp = gethostbyaddr((char *) &sin->sin_addr,
  217.                 sizeof(sin->sin_addr),
  218.                 AF_INET)) == 0) {
  219.     return (0);
  220.     }
  221.     f->name = strncpy(name_buf, hp->h_name, sizeof(name_buf) - 1);
  222.     name_buf[sizeof(name_buf) - 1] = 0;
  223.  
  224.     /*
  225.      * Verify that the host name does not belong to someone else. If host
  226.      * name verification fails, pretend that the host name lookup failed.
  227.      */
  228.  
  229.     if (ip_match(f->name, sin->sin_addr)) {
  230.     return (0);
  231.     } else {
  232.     f->name = FROM_UNKNOWN;
  233.     return (-1);                /* verification failed */
  234.     }
  235. }
  236.  
  237. /* ip_match - determine if host name matches IP address */
  238.  
  239. static int ip_match(remotehost, addr)
  240. char   *remotehost;
  241. struct in_addr addr;
  242. {
  243.     struct hostent *hp;
  244.     int     i;
  245.  
  246.     if ((hp = gethostbyname(remotehost)) == 0) {
  247.  
  248.     /*
  249.      * Unable to verify that the host name matches the address. This may
  250.      * be a transient problem or a botched name server setup. We decide
  251.      * to play safe.
  252.      */
  253.  
  254.     syslog(LOG_ERR, "gethostbyname(%s): host address lookup failed",
  255.            remotehost);
  256.     return (BAD);
  257.  
  258.     } else {
  259.  
  260.     /*
  261.      * Make sure that gethostbyname() returns the "correct" host name.
  262.      * Unfortunately, gethostbyname("localhost") sometimes yields
  263.      * "localhost.domain". Since the latter host name comes from the
  264.      * local DNS, we just have to trust it (all bets are off if the local
  265.      * DNS is perverted). We always check the address list, though.
  266.      */
  267.  
  268.     if (strcasecmp(remotehost, hp->h_name)
  269.         && strcasecmp(remotehost, "localhost")) {
  270.         syslog(LOG_ERR, "host name/name mismatch: %s != %s",
  271.            remotehost, hp->h_name);
  272.         return (BAD);
  273.     }
  274.  
  275.     /*
  276.      * Look up the host address in the address list we just got.
  277.      */
  278.  
  279.     for (i = 0; hp->h_addr_list[i]; i++) {
  280.         if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
  281.         return (GOOD);
  282.     }
  283.  
  284.     /*
  285.      * The host name does not map to the original host address. Perhaps
  286.      * someone has compromised a name server. More likely someone botched
  287.      * it, but that could be dangerous, too.
  288.      */
  289.  
  290.     syslog(LOG_ERR, "host name/address mismatch: %s != %s",
  291.            inet_ntoa(addr), hp->h_name);
  292.     return (BAD);
  293.     }
  294. }
  295.  
  296. /* udp_sink - absorb unreceived datagram */
  297.  
  298. static void udp_sink()
  299. {
  300.     char    buf[BUFSIZ];
  301.     struct sockaddr sa;
  302.     int     size = sizeof(sa);
  303.  
  304.     /*
  305.      * Eat up the not-yet received packet. Some systems insist on a non-zero
  306.      * source address argument in the recvfrom() call below.
  307.      */
  308.  
  309.     (void) recvfrom(0, buf, sizeof(buf), 0, &sa, &size);
  310. }
  311.